<?php
namespace xlx
{
    if (!function_exists('\xlx\co')) {
        function co($gen, ...$args)
        {
            if(\is_callable($gen)){
                try{  
                    $gen = $gen(...$args); 
                }catch(\Throwable $e){
                    return ($e);
                }
            }
            if ($gen instanceof \Generator) { 
                while ($gen->valid()) {
                    $val = $gen->current(); 
                    if ($val instanceof \Generator) { 
                        $val = co($val);  
                    }
                    if( method_exists($val,'onResolve') ){ 
                        $gen->promise = $val; //use \xlx\PrService::self()
                        return $val->onResolve(function (Throwable $error = null, $result = null)use($gen){
                            if($error){
                                $gen->throw($error); 
                            }else{
                                try{ 
                                    $gen->send($result);  
                                }catch(\Throwable $e){ 
                                    $gen->throw($e); 
                                }
                                unset($gen->promise); //bugfix
                            } 
                        });
                    }
                    if ( method_exists($val,'then') ) {  
                        $gen->promise = $val; //use \xlx\PrService::self()
                        return $val->then(function ($data) use ($gen) {
                            try{ 
                                $gen->send($data); 
                                unset($gen->promise); //bugfix
                                return co($gen);
                            }catch(\Throwable $e){ 
                                unset($gen->promise); //bugfix
                                throw $e;
                            }
                        },function($data)use($gen){
                            $gen->throw($data);
                            return co($gen);
                        }); 
                    } 
                    // $val = new \React\Promise\Promise(function($next)use($val){ 
                    //     $next($val);
                    // }); 
                    $gen->send($val);
                    continue; 
                   
                } 
                return  ($gen->getReturn()); 
            }/*else{
                return co((function($gen, $args){
                    return yield $gen(...$args);
                })($gen, $args)); 
            }*/
            return  co($gen); 
        }
    }

    if (!function_exists('xlx\async')) {
        function async($fn)
        {
            return function (...$args) use ($fn) {
                return \xlx\co($fn, ...$args);
            };
        }
    }
}
namespace xlx\co 
{
    if (!function_exists('\xlx\co\warp')) {
        function warp($fn)
        {
            return function (...$args) use ($fn) {
                return \xlx\co($fn, ...$args);
            };
        }
    }
    // if(!\function_exists('\xlx\co\abort')){ 
    //     function abort($ptr)
    //     { 
    //         if($gen = \xlx\lib\WeakRef::take($ptr)){ 
    //             if(isset($gen->promise))
    //             {
    //                 //非 Promise/A 标准代码  这里用defered 
    //                 $ref = new \ReflectionClass(\React\Promise\Promise::class);
    //                 $method = $ref->getMethod('reject');
    //                 $method->setAccessible(true);
    //                 $method->invokeArgs($gen->promise,[new \Exception("Error Process Abort", 1)]); 
    //                 //unset($gen->promise); 
    //             }
    //             else
    //             {
    //                 $gen->throw(new \Exception("Error Process Abort", 1));  
    //             }
    //         }else{
    //             throw new \Exception("Error Processing Request", 1); 
    //         }
    //     } 
    // }
    // if(!\function_exists('\xlx\co\self')){
    //     function self($parent=false)
    //     {
    //         foreach ($d=debug_backtrace() as $stack) {
    //             if (isset($stack['class']) && $stack['class']=='Generator') {    
    //                 return \xlx\lib\WeakRef::share( $parent?$stack['object']->parent:$stack['object'] ); 
    //             }
    //         }
    //         throw new \Exception("Error Processing Request", 1); 
    //     }
    // }
    // if(!\class_exists('\xlx\co\ptr')){ 
    //     class ptr { 
    //         // private static $objs=[];
    //         // private static $counts=[];
    //         function __construct($v){
    //             $this->hash = spl_object_hash($v);
    //             if(!isset($GLOBALS['__counts__'][$this->hash])){
    //                 $GLOBALS['__counts__'][$this->hash]=0;
    //             }
    //             $GLOBALS['__objs__'][$this->hash] = $v;
    //             $GLOBALS['__counts__'][$this->hash]++; 
    //         }
    //         function __destruct(){
    //             $GLOBALS['__counts__'][$this->hash]--; 
    //             if(0>=$GLOBALS['__counts__'][$this->hash]){
    //                 unset($GLOBALS['__objs__'][$this->hash]);
    //                 unset($GLOBALS['__counts__'][$this->hash]);
    //             }
    //         }
    //         function __toString(){
    //             return $this->hash;
    //         }
    //         public static function load($d){
    //             if($d instanceof ptr){
    //                 $d = $d->hash;
    //             }
    //             return $GLOBALS['__objs__'][$d];
    //         }
    //         public static function save($v){
    //             return new ptr($v);
    //         }    
    //     }
    // }
}




/*

\xlx\co(function(){
    echo 1; 
    echo yield 2;
    echo yield new \React\Promise\Promise(function ($next)  {
        $next(3);
    }); 
    echo yield (function(){
        return 4;
    })();   
    echo yield (function(){
        return yield 5;
    })(); 
    echo yield (function(){
        return new \React\Promise\Promise(function ($next)  {
            $next(6);
        }); 
    })();   
    echo yield (function(){
        return yield new \React\Promise\Promise(function ($next)  {
            $next(7);
        }); 
    })();    
    echo '|';
    try{   
        echo yield new \React\Promise\Promise(function ($next)  {
            throw new Exception("Error Processing Request", 1); 
            $next(1);
        }); 
    }catch(Throwable $e){
        echo yield (function(){
            return 2;
        })();    
    }
    echo '|';
    try{   
        throw new Exception("Error Processing Request", 1); 
        echo yield new \React\Promise\Promise(function ($next)  {
            $next(1);
        }); 
    }catch(Throwable $e){
        echo yield (function(){
            return 2;
        })();    
    }
    echo '|';
    echo yield (function(){
        return new \React\Promise\Promise(function ($next)  {
            $next(2);
        }); 
    })();  
}); 
exit;//1234567|2|2|2
*/